/**
 * @author 0283000115
 * @date 2018年3月5日-上午11:09:11
 */
package com.zte.claa.inficombo.csa.app.dao.mysql.jdbcdao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.pool.DruidDataSource;
import com.zte.claa.inficombo.csa.app.model.redis.DevMeteData;

/**
 * @author 0283000115
 * 
 * 1、实现claa自研Lora/蓝牙定位数据入库，支持批量入库，提升效率.
 * 2、Lora定位原始数据存储到combodb库中，方便LCS服务访问.
 *
 */
public class ClaaLocRawDataDao extends BaseDao {
	public static final String COMBODB_NAME = "combodb";
	
	// dateformat
	// public static final SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");	
	// public static String INSERT_SQL = "insert into _TABLE_NAME_(report_time, deveui, cname, cvalue) values(?,?,?,?)";
	
	// 日志管理器
	private Logger logger = LoggerFactory.getLogger(ClaaLocRawDataDao.class);
	
	/**
	 * 构建器
	 * 
	 * @param dataSource
	 */
	public ClaaLocRawDataDao(DruidDataSource dataSource){
		super(dataSource);
	}
	
	/**
	 * 根据项目id获取对应的库名。
	 * 
	 * @param projectId
	 * @return
	 */
	public String getProjDBName(String projectId){
		// return "db_"+projectId.toLowerCase().trim();
		return COMBODB_NAME;
	}
	
	/**
	 * 保存metedata
	 * 
	 * @param meteData
	 * @throws Exception
	 */
	public void saveLocRawData(DevMeteData meteData, String tabName) throws Exception {
		Map<String, Object> dmap = meteData.getMdata();
		if(dmap == null || dmap.size() == 0){
			logger.warn("No mete data field to be saved to table: "+tabName);
			return;
		}
		String[] fnmArr = this.getFieldNames(meteData);
		String pdbName = this.getProjDBName(meteData.getProjectid());
		String sql = this.buildInsertSQL(fnmArr, tabName, pdbName);
		PreparedStatement statement = null;
		Connection dbConn = this.getDBConnection();		
		try {
			statement = dbConn.prepareStatement(sql);	
			// 准备数据.
			Timestamp rptTime = meteData.getRpttime();
			String devEui = meteData.getDeveui();
			statement.setTimestamp(1, rptTime);
			statement.setString(2, devEui);
			if(fnmArr != null){
				int len = fnmArr.length;
				for(int i=0; i<len; i++){
					String fnm = fnmArr[i];
					Object fva = dmap.get(fnm);
					// fva = (fva == null) ? "0" : fva;
					statement.setObject(i+3, fva);
				}
			}
			statement.execute();
			// autocommit mode...
			// dbConn.commit();
		} finally {
			this.releaseStatement(statement);
			this.releaseConnection(dbConn);			
		}		
	}
	
	/**
	 * 批量保存metedata，要求相同类型相同字段；
	 * 
	 * @param meteData
	 * @throws Exception
	 */
	public void saveLocRawDataByBatch(List<DevMeteData> meteDatas, String tabName) throws Exception {
		if(meteDatas == null || meteDatas.size() == 0){
			logger.warn("There is no data row to be saved: "+tabName);
			return;
		}
		DevMeteData meteData1 = meteDatas.get(0);
		String[] fnmArr = this.getFieldNames(meteData1);
		String pdbName = this.getProjDBName(meteData1.getProjectid());
		String sql = this.buildInsertSQL(fnmArr, tabName, pdbName);
		PreparedStatement statement = null;
		Connection dbConn = this.getDBConnection();		
		try {
			statement = dbConn.prepareStatement(sql);	
			int batchNum = 0;
			for(DevMeteData meteData : meteDatas){
				if(meteData == null){
					continue;
				}
				Map<String, Object> dmap = meteData.getMdata();
				if(dmap == null || dmap.size() == 0){
					continue;
				}
				// 准备数据.
				Timestamp rptTime = meteData.getRpttime();
				String devEui = meteData.getDeveui();
				statement.setTimestamp(1, rptTime);
				statement.setString(2, devEui);
				if(fnmArr != null){
					int len = fnmArr.length;
					for(int i=0; i<len; i++){
						String fnm = fnmArr[i];
						Object fva = dmap.get(fnm);
						// fva = (fva == null) ? "0" : fva; 
						statement.setObject(i+3, fva);
					}
				}
				statement.addBatch();
				batchNum++;
				// 最大50一批.
				if (batchNum >= 50) {
					statement.executeBatch();					
					logger.info("Save data to table: "+tabName+", batchnum="+batchNum);
					batchNum = 0;
				}
			}
			if (batchNum > 0) {
				statement.executeBatch();
				logger.info("Save data to table: "+tabName+", batchnum="+batchNum);
			}
			// autocommit mode...
			// dbConn.commit();
		} finally {
			this.releaseStatement(statement);
			this.releaseConnection(dbConn);			
		}
	}
	
	/**
	 * 构造入库脚本。
	 * 
	 * lcs的原始数据表中时间字段是 report_time，不是通用的collecttime.
	 * 
	 * @param meteData
	 * @param tabName
	 * @return
	 */
	private String buildInsertSQL(String[] fnmArr, String tabName, String pdbName){		
		StringBuilder sb = new StringBuilder();
		sb.append("insert into").append(" ").append(pdbName).append(".").append(tabName).append("(report_time, deveui");
		StringBuilder sb2 = new StringBuilder();
		sb2.append(" ").append("values(?,?");
		if(fnmArr != null){
			int len = fnmArr.length;
			for(int i=0; i<len; i++){
				sb.append(", ").append(fnmArr[i]);
				sb2.append(", ").append("?");
			}
		}
		sb.append(")");
		sb2.append(")");
		sb.append(sb2.toString());
		return sb.toString();
	}
	
	/**
	 * 构造入库脚本。
	 * 
	 * @param meteData
	 * @param tabName
	 * @return
	 */
	private String[] getFieldNames(DevMeteData meteData){		
		List<String> fnmList = new ArrayList<String>();
		Map<String, Object> fmap = meteData.getMdata();
		if(fmap != null){
			Iterator<String> it = fmap.keySet().iterator();
			while(it.hasNext()){
				String fnm = it.next();
				fnmList.add(fnm);
			}
		}
		return (String[])fnmList.toArray(new String[fnmList.size()]);
	}

}
